package com.hexacta.hrs.domain.staffing.relationship.generators;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;

import com.hexacta.hrs.domain.staffing.Particionador;
import com.hexacta.hrs.domain.staffing.Requirement;
import com.hexacta.hrs.domain.staffing.assignment.EmployeeAssignment;

/**
 * Contiene metodos que ayudan a los generators de staffing.
 * @author ncortinez
 *
 */
public class RelationshipGeneratorUtil {

	/**
	 * Crea una nueva asignacion identica a la pasada por parametro,
	 *  pero con un porcentaje igual al  porcentaje de la asigignacion - porc de requerim.
	 * @param assignment
	 * @param req
	 * @return
	 */
	public static EmployeeAssignment crearAsignacionRestante(EmployeeAssignment assignment, Requirement req) {
		double porcentajeDeMas =  assignment.getAssignmentPorcentage() - req.getAssignmentPorcentage();
		try {
			EmployeeAssignment asignacionRestante = (EmployeeAssignment) assignment.clone();
			asignacionRestante.setAssignmentPorcentage(porcentajeDeMas);
			return asignacionRestante;
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * Genera las relaciones cuando existe un requerimiento que cubre la asignacion con un porcentaje mayor al de esta.
	 * @param assignment
	 * @param requirement
	 * @return lista con las particiones generadas del requerimiento.
	 */
	public static List<Requirement> generarRelacionesDeRequerimientoConPorcentajeMayor(EmployeeAssignment assignment, Requirement requirement) {
	 	List<Requirement> particiones = new ArrayList<Requirement>();
		//Particiono el requerimiento en la cantidad que sea necesario.
	 	particiones.addAll(Particionador.particionarExcluyendoInterseccion(requirement, assignment));
	 	
	 	// A la particion que ya fue asignada, lo pongo lo que le resta sin asignar, si es que le queda todavia un porcentaje por asignar.
	 	double porcentajeFaltantePorAsignar = requirement.getAssignmentPorcentage() - assignment.getAssignmentPorcentage();
	 	if(porcentajeFaltantePorAsignar > 0){
		 	Requirement interseccion = Particionador.obtenerInterseccion(requirement, assignment);
		 	interseccion.setAssignmentPorcentage(porcentajeFaltantePorAsignar);
		 	particiones.add(interseccion);
	 	}
	 	
	 	return particiones;
	}

	/**
	 * Busca un requerimiento que este incluido en la asignacion, y particiona esta ultima por fechas 
	 *   para que una de sus partes quede incluida en el rango de fecahs del requerimiento.
	 * @param assignment
	 * @param requirements
	 * @return
	 */
	public static List<EmployeeAssignment> particionarAsignacionSegunRequerimientos(
			EmployeeAssignment assignment, List<Requirement> requirements) {
		Requirement requerimiento = (Requirement)CollectionUtils.find(requirements, new RequerimientoIncluidoEnAsignacion(assignment));
		List<EmployeeAssignment> particiones = new ArrayList<EmployeeAssignment>();
		if(requerimiento!=null){
			particiones.addAll(Particionador.particionar(assignment, requerimiento));
		}
		return particiones;
	}
}

class RequerimientoIncluidoEnAsignacion implements Predicate {

	private Calendar startDate;
	private Calendar endDate;
	private String rol;
	
	public RequerimientoIncluidoEnAsignacion(EmployeeAssignment assignment) {
		this.startDate = assignment.getStartDate();
		this.endDate = assignment.getEndDate();
		this.rol = assignment.getAssignedRole().getDescription();
	}

	@Override
	public boolean evaluate(Object arg) {
		Requirement req = (Requirement)arg;
		
		if(!req.getRequiredRol().getDescription().equals(rol)) return false;
		
		boolean startDateIncluido = (req.getStartDate().compareTo(startDate) >= 0) && (req.getStartDate().compareTo(endDate) <= 0);
		boolean endDateIncluido = (req.getEndDate().compareTo(endDate) <= 0) && (req.getEndDate().compareTo(startDate) >= 0);
		
		return (startDateIncluido || endDateIncluido);
	}
}
